package com.block.source.service.impl;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.block.common.annotate.RedisLock;
import com.block.common.config.CommonConfig;
import com.block.common.constant.RedisKeyConstant;
import com.block.common.enums.InfoTypeEnum;
import com.block.common.exception.NotifyExceptionService;
import com.block.common.model.dto.RequestTimeDTO;
import com.block.common.model.dto.SourceCountDTO;
import com.block.common.model.vo.ResultInfoVO;
import com.block.common.mq.MqSourceCountSendService;
import com.block.common.service.IApplicationInfoService;
import com.block.common.service.ISystemRequestTimeRecordService;
import com.block.common.service.LogFactory;
import com.block.common.service.merchant.IMerchantThirdBaseInfoService;
import com.block.db.entity.*;
import com.block.db.mapper.MerchantThirdProtocolInfoMapper;
import com.block.match.enums.OrderStatusEnum;
import com.block.match.model.dto.SourceMatchResultDTO;
import com.block.match.model.dto.SourceRegisterResultDTO;
import com.block.match.service.IDataMatchOrderItemService;
import com.block.match.service.ISourceMatchHandleService;
import com.block.source.model.param.UserDataParam;
import com.block.source.service.ISourceMemberDataInfoService;
import com.block.source.service.ISourceMemberDataInfoTempService;
import com.block.source.service.ISourcePushResultInfoService;
import com.block.source.service.ISourceRegisterUserService;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

@Service
public class SourceRegisterUserService implements ISourceRegisterUserService {

    private static final Logger log = LogFactory.getSourceLog();
    private static final Logger unionLog = LogFactory.getUnionLog();

    @Autowired
    ISourcePushResultInfoService sourcePushResultInfoService;
    @Autowired
    ISourceMemberDataInfoTempService sourceMemberDataInfoTempService;
    @Autowired
    ISourceMemberDataInfoService sourceMemberDataInfoService;
    @Autowired
    IApplicationInfoService applicationInfoService;
    @Autowired
    ISourceMatchHandleService sourceMatchHandleService;
    @Autowired
    NotifyExceptionService notifyExceptionService;
    @Autowired
    MqSourceCountSendService mqSourceCountSendService;
    @Autowired
    ISystemRequestTimeRecordService systemRequestTimeRecordService;
    @Autowired
    IDataMatchOrderItemService dataMatchOrderItemService;
    @Autowired
    IMerchantThirdBaseInfoService merchantThirdBaseInfoService;
    @Resource
    MerchantThirdProtocolInfoMapper merchantThirdProtocolInfoMapper;

    @Override
    @RedisLock(lockName = "SOURCE:REGISTER:ORDER:", key = "#orderNo" )
    public ResultInfoVO sourceRegisterUser1(String orderNo, SourceBaseInfo sourceBaseInfo, UserDataParam userDataParam) {

        try {
            CountDownLatch countDownLatch = new CountDownLatch(1);
            Future<ResultInfoVO> merchantInfoFuture = ThreadUtil.execAsync(new Callable<ResultInfoVO>(){
                @Override
                public ResultInfoVO call() throws Exception {

                    ResultInfoVO resultInfoVO = sourceRegisterUser(orderNo, sourceBaseInfo, userDataParam);
                    countDownLatch.countDown();
                    return resultInfoVO;
                }

            });

            // 撞库时间
            long  registerTimeout = sourceBaseInfo.getRegisterTimeout() - 100;
            countDownLatch.await(registerTimeout, TimeUnit.MILLISECONDS);

            if (merchantInfoFuture.isDone()){
                ResultInfoVO resultInfoVO = merchantInfoFuture.get();
                return resultInfoVO;
            }

            // 异步执行，更新结果
            unionLog.info("【进件超时】【channelCode】{}【channelName】{}【orderNo】{}", sourceBaseInfo.getChannelCode(), sourceBaseInfo.getChannelName(), orderNo);

        }catch (Exception exception){
            exception.printStackTrace();
            String message = StrUtil.format("【channelCode】{}【channelName】{}【data】{}",
            sourceBaseInfo.getChannelCode(), sourceBaseInfo.getChannelName(), JSON.toJSONString(userDataParam));
            notifyExceptionService.notifyNoticeInfo("SOURCE_REGISTER_EXC", "注册操作异常", message, exception);
        }
        return ResultInfoVO.error("进件失败");
    }

    @Override
//    @RedisLock(lockName = "SOURCE:REGISTER:ORDER:", key = "#orderNo" )
    public ResultInfoVO sourceRegisterUser(String orderNo, SourceBaseInfo sourceBaseInfo, UserDataParam userDataParam) {

            Long time0 = System.currentTimeMillis();

            log.info("【线索注册】【channelCode】{}【channelName】{}【UserDataParam】{}",
                    sourceBaseInfo.getChannelCode(), sourceBaseInfo.getChannelName(), JSON.toJSONString(userDataParam));

            //
            SourceCountDTO sourceCountDTO = new SourceCountDTO(sourceBaseInfo.getChannelCode(), sourceBaseInfo.getChannelName());
            sourceCountDTO.setRegisterNumber(1);
            mqSourceCountSendService.sourceDataCountSend(sourceCountDTO);

            Long time00 = System.currentTimeMillis();

            SourcePushResultInfo pushResultInfo = sourcePushResultInfoService.getById(userDataParam.getOrderNo());
            if (ObjectUtil.isEmpty(pushResultInfo)){
                return ResultInfoVO.error("订单号错误");
            }
            if (!StrUtil.equals(pushResultInfo.getStatus(), OrderStatusEnum.INIT.getValue())){
                return ResultInfoVO.error("订单状态错误");
            }
            // 订单超时
            boolean timeoutFlag = LocalDateTime.now().isAfter(pushResultInfo.getCreateTime().plusMinutes(30L));
            if (timeoutFlag){
                return ResultInfoVO.error("订单超时");
            }

            Long time1 = System.currentTimeMillis();
            // 进件手机号查重
//            MemberBaseInfo memberBaseInfo = memberBaseInfoMapper.getBaseUserInfoByPhoneLock(userDataParam.getMobile());
//            if (ObjectUtil.isNotEmpty(memberBaseInfo)){
//                return ResultInfoVO.error("用户已经存在");
//            }

            String mobileMd5 = SecureUtil.md5(userDataParam.getMobile()).toLowerCase();
            SourceMemberDataInfoTemp memberDataInfoTemp = sourceMemberDataInfoTempService.getById(pushResultInfo.getDataId());
            if (!StrUtil.equals(mobileMd5, memberDataInfoTemp.getMobileMd5())){
                return ResultInfoVO.error("与撞库手机号不同");
            }

            Long time11 = System.currentTimeMillis();

            /// 保存用户资质信息
            ResultInfoVO resultInfoVO = sourceMemberDataInfoTempService.updateDataInfo(memberDataInfoTemp, userDataParam, pushResultInfo);
            log.info("【线索注册】保存用户资质信息【resultInfoVO】{}", JSON.toJSONString(resultInfoVO));
            if (!resultInfoVO.isSuccess()){
                return resultInfoVO;
            }

            Long time2 = System.currentTimeMillis();

            JSONObject data = resultInfoVO.getData();
            MemberSourceInfo memberSourceInfo = data.getObject("memberSourceInfo", MemberSourceInfo.class);

            // 继续操作订单信息
            SourceMatchResultDTO resultDTO = new SourceMatchResultDTO();
            resultDTO.setOrderNo(pushResultInfo.getOrderNo());
            resultDTO.setOrderItemNo(pushResultInfo.getOrderItemNo());

            //处理注册信息
            SourceRegisterResultDTO registerResultDTO = sourceMatchHandleService.handleRegisterUser(sourceBaseInfo, resultDTO, memberSourceInfo);
            log.info("【线索注册】执行注册【registerResultDTO】{}", JSON.toJSONString(registerResultDTO));
            if (!registerResultDTO.isSuccess()){
                return ResultInfoVO.error("信息注册失败");
            }

            Long time3 = System.currentTimeMillis();

            sourceCountDTO.setRegisterPassNumber(1);
            sourceCountDTO.setRegisterNumber(null);
            mqSourceCountSendService.sourceDataCountSend(sourceCountDTO);

            // 请求成功，根据线索类型，判断是否需要返回
            JSONObject returnObject = new JSONObject();
            returnObject.put("status", "000");
            if (StrUtil.equals(sourceBaseInfo.getType(), InfoTypeEnum.APIB.getValue()) ||
                    StrUtil.equals(sourceBaseInfo.getType(), InfoTypeEnum.APIB_S.getValue())){
                // url 授权回调
                ApplicationInfo appInfoByAppCode = applicationInfoService.getAppInfoByAppCode(memberDataInfoTemp.getAppCode());
                String approveUrl = StrUtil.format(appInfoByAppCode.getSourceUrl(), pushResultInfo.getId());

                SourcePushResultInfo updateResult = new SourcePushResultInfo();
                updateResult.setId(pushResultInfo.getId());
                updateResult.setStatus(OrderStatusEnum.WAIT_PUSH.getValue());
                updateResult.setApproveUrl(approveUrl);
                sourcePushResultInfoService.updateById(updateResult);

                returnObject.put("approveUrl", approveUrl);
            }else{
                // api直接推送 / apis 双授权 需要直接推送到商户账号下
                // 异步执行推送到商户逻辑
                if (StrUtil.equals(InfoTypeEnum.APIS.getValue(), pushResultInfo.getInfoType())){
                    String orderItemNo = pushResultInfo.getOrderItemNo();
                    DataMatchOrderItem matchOrderItem = dataMatchOrderItemService.getById(orderItemNo);
                    MerchantThirdBaseInfo thirdBaseInfo = merchantThirdBaseInfoService.selectEntityByOrderNo(matchOrderItem.getPushId());
                    List<MerchantThirdProtocolInfo> thirdProtocolInfoList = merchantThirdProtocolInfoMapper.selectListByThirdId(thirdBaseInfo.getId());

                    returnObject.put("thirdBaseInfo", thirdBaseInfo);
                    returnObject.put("thirdProtocolInfoList", thirdProtocolInfoList);
                }
                SourceRegisterResultDTO pushResult = sourcePushResultInfoService.handlePushToMerchant(pushResultInfo);
                log.info("【线索注册】api注册类型，推送完整【pushResult】{}", JSON.toJSONString(pushResult));

                if (pushResult.isSuccess() && !pushResult.isLessNumberFlag()){
                    // 推送成功，且不扣量，，，返回进件成功
                    returnObject.put("remark", "进件完成");
                }else{
                    returnObject.put("status", "002");
                    returnObject.put("remark", "进件失败");
                }
            }


            Long time9 = System.currentTimeMillis();
            if (time9-time0 > 2000){
                RequestTimeDTO timeDTO = new RequestTimeDTO();
                timeDTO.setBizType("SOURCE_REGISTER_RECORD");
                timeDTO.setBizName("线索进件流程分步记录");
                timeDTO.setExecTime(String.valueOf(time9- time0));
                timeDTO.setParamInfo(StrUtil.format("【channelCode】{}【channelName】{}【orderNo】{}", sourceBaseInfo.getChannelCode(), sourceBaseInfo.getChannelName(), orderNo));
                timeDTO.setResultInfo(JSON.toJSONString(resultDTO));
                timeDTO.setRemarkInfo(StrUtil.format("【time9-time3】{}【time3-time2】{}【time2-time11】{}【time11-time1】{}【time1-time0】{}【time00-time0】{}",
                        time9-time3,time3-time2,time2-time11, time11-time1 ,time1-time00 ,time00-time0));
                systemRequestTimeRecordService.saveRequestTime(timeDTO);
            }

            return ResultInfoVO.success(returnObject);
//        } catch (Exception exception) {
//            exception.printStackTrace();
//            String message = StrUtil.format("【channelCode】{}【channelName】{}【data】{}",
//                    sourceBaseInfo.getChannelCode(), sourceBaseInfo.getChannelName(), JSON.toJSONString(userDataParam));
//            notifyExceptionService.notifyNoticeInfo("SOURCE_REGISTER_EXC", "注册操作异常", message, exception);
//        }
//        return ResultInfoVO.error("操作异常");
    }

}
